package com.interview.javabasic.IO;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

/*
@李子宁
Happy,happy everyday!
冲鸭！
2021/2/28

*/
public class NIOServer {

    public static void main(String[] args) throws IOException {
        //1.serverselector负责轮询是否有新的连接，服务器端检测到新的连接之后，不再创建一个新的线程
        //而是直接将新连接绑定到clientSelector上，这样就不用IO模型中的while循环了
        Selector serverSelector = Selector.open();
        //2.clientSelector负责轮询连接是否有数可以读取
        Selector clientSelector = Selector.open();

        new Thread(() ->{
            //对应IO编程中服务器端启动
            try {
                ServerSocketChannel listenerChannel = ServerSocketChannel.open();
                listenerChannel.socket().bind(new InetSocketAddress(3333));
                listenerChannel.configureBlocking(false);
                listenerChannel.register(serverSelector, SelectionKey.OP_ACCEPT);
                while (true){
                    if (serverSelector.select(1) > 0){
                        Set<SelectionKey> set = serverSelector.selectedKeys();
                        Iterator<SelectionKey> keyIter = set.iterator();

                        while(keyIter.hasNext()){
                            SelectionKey next = keyIter.next();
                            if(next.isAcceptable()){
                                try{
                                    //每来一个新连接，不需要创建一个线程，而是直接注册到clientServer里面
                                    SocketChannel clientChannel = ((ServerSocketChannel) next.channel()).accept();
                                    clientChannel.configureBlocking(false);
                                    clientChannel.register(clientSelector,SelectionKey.OP_READ);
                                }finally {
                                    keyIter.remove();
                                }
                            }
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() ->{
            //批量轮询是否有哪些连接有数据可读，这里的1是阻塞的时间为1秒
            try {
                while (true){
                    if (clientSelector.select(1) > 0){

                            Set<SelectionKey> selectionKeys = clientSelector.selectedKeys();
                            Iterator<SelectionKey> iterator = selectionKeys.iterator();
                            while (iterator.hasNext()){
                                SelectionKey next = iterator.next();
                                if (next.isReadable()){
                                    try{
                                    SocketChannel clientChannel = (SocketChannel) next.channel();
                                    ByteBuffer allocate = ByteBuffer.allocate(1024);
                                    //3.面向buffer
                                    clientChannel.read(allocate);
                                    allocate.flip();
                                    System.out.println(Charset.defaultCharset().newDecoder().decode(allocate).toString());
                                    }finally {
                                        iterator.remove();
                                        next.interestOps(SelectionKey.OP_READ);
                                    }
                                }
                            }

                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally {

            }
        }).start();
    }
}
